WaveFileReader.readDataChunk_   A
last analyzed

Complexity

Conditions 3

Size

Total Lines 15
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 11
dl 0
loc 15
rs 9.85
c 0
b 0
f 0
cc 3
1
/*
2
 * Copyright (c) 2017-2019 Rafael da Silva Rocha.
3
 *
4
 * Permission is hereby granted, free of charge, to any person obtaining
5
 * a copy of this software and associated documentation files (the
6
 * "Software"), to deal in the Software without restriction, including
7
 * without limitation the rights to use, copy, modify, merge, publish,
8
 * distribute, sublicense, and/or sell copies of the Software, and to
9
 * permit persons to whom the Software is furnished to do so, subject to
10
 * the following conditions:
11
 *
12
 * The above copyright notice and this permission notice shall be
13
 * included in all copies or substantial portions of the Software.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
 *
23
 */
24
25
/**
26
 * @fileoverview The WaveFileReader class.
27
 * @see https://github.com/rochars/wavefile
28
 */
29
30
import { RIFFFile } from './riff-file';
31
import { unpackString, unpack } from './parsers/binary';
32
33
/**
34
 * A class to read wav files.
35
 * @extends RIFFFile
36
 */
37
export class WaveFileReader extends RIFFFile {
38
39
  constructor() {
40
    super();
41
    // Include 'RF64' as a supported container format
42
    this.supported_containers.push('RF64');
43
    /**
44
     * The data of the 'fmt' chunk.
45
     * @type {!Object<string, *>}
46
     */
47
    this.fmt = {
48
      /** @type {string} */
49
      chunkId: '',
50
      /** @type {number} */
51
      chunkSize: 0,
52
      /** @type {number} */
53
      audioFormat: 0,
54
      /** @type {number} */
55
      numChannels: 0,
56
      /** @type {number} */
57
      sampleRate: 0,
58
      /** @type {number} */
59
      byteRate: 0,
60
      /** @type {number} */
61
      blockAlign: 0,
62
      /** @type {number} */
63
      bitsPerSample: 0,
64
      /** @type {number} */
65
      cbSize: 0,
66
      /** @type {number} */
67
      validBitsPerSample: 0,
68
      /** @type {number} */
69
      dwChannelMask: 0,
70
      /**
71
       * 4 32-bit values representing a 128-bit ID
72
       * @type {!Array<number>}
73
       */
74
      subformat: []
75
    };
76
    /**
77
     * The data of the 'fact' chunk.
78
     * @type {!Object<string, *>}
79
     */
80
    this.fact = {
81
      /** @type {string} */
82
      chunkId: '',
83
      /** @type {number} */
84
      chunkSize: 0,
85
      /** @type {number} */
86
      dwSampleLength: 0
87
    };
88
    /**
89
     * The data of the 'cue ' chunk.
90
     * @type {!Object<string, *>}
91
     */
92
    this.cue = {
93
      /** @type {string} */
94
      chunkId: '',
95
      /** @type {number} */
96
      chunkSize: 0,
97
      /** @type {number} */
98
      dwCuePoints: 0,
99
      /** @type {!Array<!Object>} */
100
      points: [],
101
    };
102
    /**
103
     * The data of the 'smpl' chunk.
104
     * @type {!Object<string, *>}
105
     */
106
    this.smpl = {
107
      /** @type {string} */
108
      chunkId: '',
109
      /** @type {number} */
110
      chunkSize: 0,
111
      /** @type {number} */
112
      dwManufacturer: 0,
113
      /** @type {number} */
114
      dwProduct: 0,
115
      /** @type {number} */
116
      dwSamplePeriod: 0,
117
      /** @type {number} */
118
      dwMIDIUnityNote: 0,
119
      /** @type {number} */
120
      dwMIDIPitchFraction: 0,
121
      /** @type {number} */
122
      dwSMPTEFormat: 0,
123
      /** @type {number} */
124
      dwSMPTEOffset: 0,
125
      /** @type {number} */
126
      dwNumSampleLoops: 0,
127
      /** @type {number} */
128
      dwSamplerData: 0,
129
      /** @type {!Array<!Object>} */
130
      loops: []
131
    };
132
    /**
133
     * The data of the 'bext' chunk.
134
     * @type {!Object<string, *>}
135
     */
136
    this.bext = {
137
      /** @type {string} */
138
      chunkId: '',
139
      /** @type {number} */
140
      chunkSize: 0,
141
      /** @type {string} */
142
      description: '', //256
143
      /** @type {string} */
144
      originator: '', //32
145
      /** @type {string} */
146
      originatorReference: '', //32
147
      /** @type {string} */
148
      originationDate: '', //10
149
      /** @type {string} */
150
      originationTime: '', //8
151
      /**
152
       * 2 32-bit values, timeReference high and low
153
       * @type {!Array<number>}
154
       */
155
      timeReference: [0, 0],
156
      /** @type {number} */
157
      version: 0, //WORD
158
      /** @type {string} */
159
      UMID: '', // 64 chars
160
      /** @type {number} */
161
      loudnessValue: 0, //WORD
162
      /** @type {number} */
163
      loudnessRange: 0, //WORD
164
      /** @type {number} */
165
      maxTruePeakLevel: 0, //WORD
166
      /** @type {number} */
167
      maxMomentaryLoudness: 0, //WORD
168
      /** @type {number} */
169
      maxShortTermLoudness: 0, //WORD
170
      /** @type {string} */
171
      reserved: '', //180
172
      /** @type {string} */
173
      codingHistory: '' // string, unlimited
174
    };
175
    /**
176
     * The data of the 'iXML' chunk.
177
     * @type {!Object<string, *>}
178
     */
179
    this.iXML = {
180
      /** @type {string} */
181
      chunkId: '',
182
      /** @type {number} */
183
      chunkSize: 0,
184
      /** @type {string} */
185
      value: ''
186
    };
187
    /**
188
     * The data of the 'ds64' chunk.
189
     * Used only with RF64 files.
190
     * @type {!Object<string, *>}
191
     */
192
    this.ds64 = {
193
      /** @type {string} */
194
      chunkId: '',
195
      /** @type {number} */
196
      chunkSize: 0,
197
      /** @type {number} */
198
      riffSizeHigh: 0, // DWORD
199
      /** @type {number} */
200
      riffSizeLow: 0, // DWORD
201
      /** @type {number} */
202
      dataSizeHigh: 0, // DWORD
203
      /** @type {number} */
204
      dataSizeLow: 0, // DWORD
205
      /** @type {number} */
206
      originationTime: 0, // DWORD
207
      /** @type {number} */
208
      sampleCountHigh: 0, // DWORD
209
      /** @type {number} */
210
      sampleCountLow: 0 // DWORD
211
      /** @type {number} */
212
      //'tableLength': 0, // DWORD
213
      /** @type {!Array<number>} */
214
      //'table': []
215
    };
216
    /**
217
     * The data of the 'data' chunk.
218
     * @type {!Object<string, *>}
219
     */
220
    this.data = {
221
      /** @type {string} */
222
      chunkId: '',
223
      /** @type {number} */
224
      chunkSize: 0,
225
      /** @type {!Uint8Array} */
226
      samples: new Uint8Array(0)
227
    };
228
    /**
229
     * The data of the 'LIST' chunks.
230
     * Each item in this list look like this:
231
     *  {
232
     *      chunkId: '',
233
     *      chunkSize: 0,
234
     *      format: '',
235
     *      subChunks: []
236
     *   }
237
     * @type {!Array<!Object>}
238
     */
239
    this.LIST = [];
240
    /**
241
     * The data of the 'junk' chunk.
242
     * @type {!Object<string, *>}
243
     */
244
    this.junk = {
245
      /** @type {string} */
246
      chunkId: '',
247
      /** @type {number} */
248
      chunkSize: 0,
249
      /** @type {!Array<number>} */
250
      chunkData: []
251
    };
252
    /**
253
     * The data of the '_PMX' chunk.
254
     * @type {!Object<string, *>}
255
     */
256
    this._PMX = {
257
      /** @type {string} */
258
      chunkId: '',
259
      /** @type {number} */
260
      chunkSize: 0,
261
      /** @type {string} */
262
      value: ''
263
    };
264
    /**
265
     * @type {{be: boolean, bits: number, fp: boolean, signed: boolean}}
266
     * @protected
267
     */
268
    this.uInt16 = {bits: 16, be: false, signed: false, fp: false};
269
  }
270
271
  /**
272
   * Set up the WaveFileReader object from a byte buffer.
273
   * @param {!Uint8Array} wavBuffer The buffer.
274
   * @param {boolean=} [samples=true] True if the samples should be loaded.
275
   * @throws {Error} If container is not RIFF, RIFX or RF64.
276
   * @throws {Error} If format is not WAVE.
277
   * @throws {Error} If no 'fmt ' chunk is found.
278
   * @throws {Error} If no 'data' chunk is found.
279
   */
280
  fromBuffer(wavBuffer, samples=true) {
281
    // Always should reset the chunks when reading from a buffer
282
    this.clearHeaders();
283
    this.setSignature(wavBuffer);
284
    this.uInt16.be = this.uInt32.be;
285
    if (this.format != 'WAVE') {
286
      throw Error('Could not find the "WAVE" format identifier');
287
    }
288
    this.readDs64Chunk_(wavBuffer);
289
    this.readFmtChunk_(wavBuffer);
290
    this.readFactChunk_(wavBuffer);
291
    this.readBextChunk_(wavBuffer);
292
    this.readiXMLChunk_(wavBuffer);
293
    this.readCueChunk_(wavBuffer);
294
    this.readSmplChunk_(wavBuffer);
295
    this.readDataChunk_(wavBuffer, samples);
296
    this.readJunkChunk_(wavBuffer);
297
    this.readLISTChunk_(wavBuffer);
298
    this.read_PMXChunk_(wavBuffer);
299
  }
300
301
  /**
302
   * Reset the chunks of the WaveFileReader instance.
303
   * @protected
304
   * @ignore
305
   */
306
  clearHeaders() {
307
    /** @type {!Object} */
308
    let tmpWav = new WaveFileReader();
309
    Object.assign(this.fmt, tmpWav.fmt);
310
    Object.assign(this.fact, tmpWav.fact);
311
    Object.assign(this.cue, tmpWav.cue);
312
    Object.assign(this.smpl, tmpWav.smpl);
313
    Object.assign(this.bext, tmpWav.bext);
314
    Object.assign(this.iXML, tmpWav.iXML);
315
    Object.assign(this.ds64, tmpWav.ds64);
316
    Object.assign(this.data, tmpWav.data);
317
    this.LIST = [];
318
    Object.assign(this.junk, tmpWav.junk);
319
    Object.assign(this._PMX, tmpWav._PMX);
320
  }
321
  
322
  /**
323
   * Read the 'fmt ' chunk of a wave file.
324
   * @param {!Uint8Array} buffer The wav file buffer.
325
   * @throws {Error} If no 'fmt ' chunk is found.
326
   * @private
327
   */
328
  readFmtChunk_(buffer) {
329
    /** @type {?Object} */
330
    let chunk = this.findChunk('fmt ');
331
    if (chunk) {
332
      this.head = chunk.chunkData.start;
333
      this.fmt.chunkId = chunk.chunkId;
334
      this.fmt.chunkSize = chunk.chunkSize;
335
      this.fmt.audioFormat = this.readUInt16_(buffer);
336
      this.fmt.numChannels = this.readUInt16_(buffer);
337
      this.fmt.sampleRate = this.readUInt32(buffer);
338
      this.fmt.byteRate = this.readUInt32(buffer);
339
      this.fmt.blockAlign = this.readUInt16_(buffer);
340
      this.fmt.bitsPerSample = this.readUInt16_(buffer);
341
      this.readFmtExtension_(buffer);
342
    } else {
343
      throw Error('Could not find the "fmt " chunk');
344
    }
345
  }
346
347
  /**
348
   * Read the 'fmt ' chunk extension.
349
   * @param {!Uint8Array} buffer The wav file buffer.
350
   * @private
351
   */
352
  readFmtExtension_(buffer) {
353
    if (this.fmt.chunkSize > 16) {
354
      this.fmt.cbSize = this.readUInt16_(buffer);
355
      if (this.fmt.chunkSize > 18) {
356
        this.fmt.validBitsPerSample = this.readUInt16_(buffer);
357
        if (this.fmt.chunkSize > 20) {
358
          this.fmt.dwChannelMask = this.readUInt32(buffer);
359
          this.fmt.subformat = [
360
            this.readUInt32(buffer),
361
            this.readUInt32(buffer),
362
            this.readUInt32(buffer),
363
            this.readUInt32(buffer)];
364
        }
365
      }
366
    }
367
  }
368
369
  /**
370
   * Read the 'fact' chunk of a wav file.
371
   * @param {!Uint8Array} buffer The wav file buffer.
372
   * @private
373
   */
374
  readFactChunk_(buffer) {
375
    /** @type {?Object} */
376
    let chunk = this.findChunk('fact');
377
    if (chunk) {
378
      this.head = chunk.chunkData.start;
379
      this.fact.chunkId = chunk.chunkId;
380
      this.fact.chunkSize = chunk.chunkSize;
381
      this.fact.dwSampleLength = this.readUInt32(buffer);
382
    }
383
  }
384
385
  /**
386
   * Read the 'cue ' chunk of a wave file.
387
   * @param {!Uint8Array} buffer The wav file buffer.
388
   * @private
389
   */
390
  readCueChunk_(buffer) {
391
    /** @type {?Object} */
392
    let chunk = this.findChunk('cue ');
393
    if (chunk) {
394
      this.head = chunk.chunkData.start;
395
      this.cue.chunkId = chunk.chunkId;
396
      this.cue.chunkSize = chunk.chunkSize;
397
      this.cue.dwCuePoints = this.readUInt32(buffer);
398
      for (let i = 0; i < this.cue.dwCuePoints; i++) {
399
        this.cue.points.push({
400
          dwName: this.readUInt32(buffer),
401
          dwPosition: this.readUInt32(buffer),
402
          fccChunk: this.readString(buffer, 4),
403
          dwChunkStart: this.readUInt32(buffer),
404
          dwBlockStart: this.readUInt32(buffer),
405
          dwSampleOffset: this.readUInt32(buffer),
406
        });
407
      }
408
    }
409
  }
410
411
  /**
412
   * Read the 'smpl' chunk of a wave file.
413
   * @param {!Uint8Array} buffer The wav file buffer.
414
   * @private
415
   */
416
  readSmplChunk_(buffer) {
417
    /** @type {?Object} */
418
    let chunk = this.findChunk('smpl');
419
    if (chunk) {
420
      this.head = chunk.chunkData.start;
421
      this.smpl.chunkId = chunk.chunkId;
422
      this.smpl.chunkSize = chunk.chunkSize;
423
      this.smpl.dwManufacturer = this.readUInt32(buffer);
424
      this.smpl.dwProduct = this.readUInt32(buffer);
425
      this.smpl.dwSamplePeriod = this.readUInt32(buffer);
426
      this.smpl.dwMIDIUnityNote = this.readUInt32(buffer);
427
      this.smpl.dwMIDIPitchFraction = this.readUInt32(buffer);
428
      this.smpl.dwSMPTEFormat = this.readUInt32(buffer);
429
      this.smpl.dwSMPTEOffset = this.readUInt32(buffer);
430
      this.smpl.dwNumSampleLoops = this.readUInt32(buffer);
431
      this.smpl.dwSamplerData = this.readUInt32(buffer);
432
      for (let i = 0; i < this.smpl.dwNumSampleLoops; i++) {
433
        this.smpl.loops.push({
434
          dwName: this.readUInt32(buffer),
435
          dwType: this.readUInt32(buffer),
436
          dwStart: this.readUInt32(buffer),
437
          dwEnd: this.readUInt32(buffer),
438
          dwFraction: this.readUInt32(buffer),
439
          dwPlayCount: this.readUInt32(buffer),
440
        });
441
      }
442
    }
443
  }
444
445
  /**
446
   * Read the 'data' chunk of a wave file.
447
   * @param {!Uint8Array} buffer The wav file buffer.
448
   * @param {boolean} samples True if the samples should be loaded.
449
   * @throws {Error} If no 'data' chunk is found.
450
   * @private
451
   */
452
  readDataChunk_(buffer, samples) {
453
    /** @type {?Object} */
454
    let chunk = this.findChunk('data');
455
    if (chunk) {
456
      this.data.chunkId = 'data';
457
      this.data.chunkSize = chunk.chunkSize;
458
      if (samples) {
459
        this.data.samples = buffer.slice(
460
          chunk.chunkData.start,
461
          chunk.chunkData.end);
462
      }
463
    } else {
464
      throw Error('Could not find the "data" chunk');
465
    }
466
  }
467
468
  /**
469
   * Read the 'bext' chunk of a wav file.
470
   * @param {!Uint8Array} buffer The wav file buffer.
471
   * @private
472
   */
473
  readBextChunk_(buffer) {
474
    /** @type {?Object} */
475
    let chunk = this.findChunk('bext');
476
    if (chunk) {
477
      this.head = chunk.chunkData.start;
478
      this.bext.chunkId = chunk.chunkId;
479
      this.bext.chunkSize = chunk.chunkSize;
480
      this.bext.description = this.readString(buffer, 256);
481
      this.bext.originator = this.readString(buffer, 32);
482
      this.bext.originatorReference = this.readString(buffer, 32);
483
      this.bext.originationDate = this.readString(buffer, 10);
484
      this.bext.originationTime = this.readString(buffer, 8);
485
      this.bext.timeReference = [
486
        this.readUInt32(buffer),
487
        this.readUInt32(buffer)];
488
      this.bext.version = this.readUInt16_(buffer);
489
      this.bext.UMID = this.readString(buffer, 64);
490
      this.bext.loudnessValue = this.readUInt16_(buffer);
491
      this.bext.loudnessRange = this.readUInt16_(buffer);
492
      this.bext.maxTruePeakLevel = this.readUInt16_(buffer);
493
      this.bext.maxMomentaryLoudness = this.readUInt16_(buffer);
494
      this.bext.maxShortTermLoudness = this.readUInt16_(buffer);
495
      this.bext.reserved = this.readString(buffer, 180);
496
      this.bext.codingHistory = this.readString(
497
        buffer, this.bext.chunkSize - 602);
498
    }
499
  }
500
501
  /**
502
   * Read the 'iXML' chunk of a wav file.
503
   * @param {!Uint8Array} buffer The wav file buffer.
504
   * @private
505
   */
506
  readiXMLChunk_(buffer) {
507
    /** @type {?Object} */
508
    let chunk = this.findChunk('iXML');
509
    if (chunk) {
510
      this.head = chunk.chunkData.start;
511
      this.iXML.chunkId = chunk.chunkId;
512
      this.iXML.chunkSize = chunk.chunkSize;
513
      this.iXML.value = unpackString(
514
        buffer, this.head, this.head + this.iXML.chunkSize);
515
    }
516
  }
517
518
  /**
519
   * Read the 'ds64' chunk of a wave file.
520
   * @param {!Uint8Array} buffer The wav file buffer.
521
   * @throws {Error} If no 'ds64' chunk is found and the file is RF64.
522
   * @private
523
   */
524
  readDs64Chunk_(buffer) {
525
    /** @type {?Object} */
526
    let chunk = this.findChunk('ds64');
527
    if (chunk) {
528
      this.head = chunk.chunkData.start;
529
      this.ds64.chunkId = chunk.chunkId;
530
      this.ds64.chunkSize = chunk.chunkSize;
531
      this.ds64.riffSizeHigh = this.readUInt32(buffer);
532
      this.ds64.riffSizeLow = this.readUInt32(buffer);
533
      this.ds64.dataSizeHigh = this.readUInt32(buffer);
534
      this.ds64.dataSizeLow = this.readUInt32(buffer);
535
      this.ds64.originationTime = this.readUInt32(buffer);
536
      this.ds64.sampleCountHigh = this.readUInt32(buffer);
537
      this.ds64.sampleCountLow = this.readUInt32(buffer);
538
      //if (wav.ds64.chunkSize > 28) {
539
      //  wav.ds64.tableLength = unpack(
540
      //    chunkData.slice(28, 32), uInt32_);
541
      //  wav.ds64.table = chunkData.slice(
542
      //     32, 32 + wav.ds64.tableLength);
543
      //}
544
    } else {
545
      if (this.container == 'RF64') {
546
        throw Error('Could not find the "ds64" chunk');
547
      }
548
    }
549
  }
550
551
  /**
552
   * Read the 'LIST' chunks of a wave file.
553
   * @param {!Uint8Array} buffer The wav file buffer.
554
   * @private
555
   */
556
  readLISTChunk_(buffer) {
557
    /** @type {?Object} */
558
    let listChunks = this.findChunk('LIST', true);
559
    if (listChunks !== null) {
560
      for (let j=0; j < listChunks.length; j++) {
561
        /** @type {!Object} */
562
        let subChunk = listChunks[j];
563
        this.LIST.push({
564
          chunkId: subChunk.chunkId,
565
          chunkSize: subChunk.chunkSize,
566
          format: subChunk.format,
567
          subChunks: []});
568
        for (let x=0; x<subChunk.subChunks.length; x++) {
569
          this.readLISTSubChunks_(subChunk.subChunks[x],
570
            subChunk.format, buffer);
571
        }
572
      }
573
    }
574
  }
575
576
  /**
577
   * Read the sub chunks of a 'LIST' chunk.
578
   * @param {!Object} subChunk The 'LIST' subchunks.
579
   * @param {string} format The 'LIST' format, 'adtl' or 'INFO'.
580
   * @param {!Uint8Array} buffer The wav file buffer.
581
   * @private
582
   */
583
  readLISTSubChunks_(subChunk, format, buffer) {
584
    if (format == 'adtl') {
585
      if (['labl', 'note','ltxt'].indexOf(subChunk.chunkId) > -1) {
586
        this.readLISTadtlSubChunks_(buffer, subChunk);
587
      }
588
    // RIFF INFO tags like ICRD, ISFT, ICMT
589
    } else if(format == 'INFO') {
590
      this.readLISTINFOSubChunks_(buffer, subChunk);
591
    }
592
  }
593
594
  /**
595
   * Read the sub chunks of a 'LIST' chunk of type 'adtl'.
596
   * @param {!Uint8Array} buffer The wav file buffer.
597
   * @param {!Object} subChunk The 'LIST' subchunks.
598
   * @private
599
   */
600
  readLISTadtlSubChunks_(buffer, subChunk) {
601
    this.head = subChunk.chunkData.start;
602
    /** @type {!Object<string, string|number>} */
603
    let item = {
604
      chunkId: subChunk.chunkId,
605
      chunkSize: subChunk.chunkSize,
606
      dwName: this.readUInt32(buffer)
607
    };
608
    if (subChunk.chunkId == 'ltxt') {
609
      item.dwSampleLength = this.readUInt32(buffer);
610
      item.dwPurposeID = this.readUInt32(buffer);
611
      item.dwCountry = this.readUInt16_(buffer);
612
      item.dwLanguage = this.readUInt16_(buffer);
613
      item.dwDialect = this.readUInt16_(buffer);
614
      item.dwCodePage = this.readUInt16_(buffer);
615
      item.value = ''; // kept for compatibility
616
    } else {
617
      item.value = this.readZSTR_(buffer, this.head);
618
    }
619
    this.LIST[this.LIST.length - 1].subChunks.push(item);
620
  }
621
622
  /**
623
   * Read the sub chunks of a 'LIST' chunk of type 'INFO'.
624
   * @param {!Uint8Array} buffer The wav file buffer.
625
   * @param {!Object} subChunk The 'LIST' subchunks.
626
   * @private
627
   */
628
  readLISTINFOSubChunks_(buffer, subChunk) {
629
    this.head = subChunk.chunkData.start;
630
    this.LIST[this.LIST.length - 1].subChunks.push({
631
      chunkId: subChunk.chunkId,
632
      chunkSize: subChunk.chunkSize,
633
      value: this.readZSTR_(buffer, this.head)
634
    });
635
  }
636
637
  /**
638
   * Read the 'junk' chunk of a wave file.
639
   * @param {!Uint8Array} buffer The wav file buffer.
640
   * @private
641
   */
642
  readJunkChunk_(buffer) {
643
    /** @type {?Object} */
644
    let chunk = this.findChunk('junk');
645
    if (chunk) {
646
      this.junk = {
647
        chunkId: chunk.chunkId,
648
        chunkSize: chunk.chunkSize,
649
        chunkData: [].slice.call(buffer.slice(
650
          chunk.chunkData.start,
651
          chunk.chunkData.end))
652
      };
653
    }
654
  }
655
656
  /**
657
   * Read the '_PMX' chunk of a wav file.
658
   * @param {!Uint8Array} buffer The wav file buffer.
659
   * @private
660
   */
661
  read_PMXChunk_(buffer) {
662
    /** @type {?Object} */
663
    let chunk = this.findChunk('_PMX');
664
    if (chunk) {
665
      this.head = chunk.chunkData.start;
666
      this._PMX.chunkId = chunk.chunkId;
667
      this._PMX.chunkSize = chunk.chunkSize;
668
      this._PMX.value = unpackString(
669
        buffer, this.head, this.head + this._PMX.chunkSize);
670
    }
671
  }
672
673
  /**
674
   * Read bytes as a ZSTR string.
675
   * @param {!Uint8Array} bytes The bytes.
676
   * @param {number=} [index=0] the index to start reading.
677
   * @return {string} The string.
678
   * @private
679
   */
680
  readZSTR_(bytes, index=0) {
681
    for (let i = index; i < bytes.length; i++) {
682
      this.head++;
683
      if (bytes[i] === 0) {
684
        break;
685
      }
686
    }
687
    return unpackString(bytes, index, this.head - 1);
688
  }
689
690
  /**
691
   * Read a number from a chunk.
692
   * @param {!Uint8Array} bytes The chunk bytes.
693
   * @return {number} The number.
694
   * @private
695
   */
696
  readUInt16_(bytes) {
697
    /** @type {number} */
698
    let value = unpack(bytes, this.uInt16, this.head);
699
    this.head += 2;
700
    return value;
701
  }
702
}
703